package net.zoneland.knowledge.scheduled;

import net.zoneland.knowledge.dao.ScheduledTaskMapper;
import net.zoneland.knowledge.enums.ScheduledTaskStatusEnum;
import net.zoneland.knowledge.model.ScheduledTask;
import net.zoneland.knowledge.service.ScheduledTaskJobService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Component
public class DynamicScheduledTask implements SchedulingConfigurer {

    @Resource
    private ScheduledTaskMapper scheduledTaskMapper;

    @Resource
    private ScheduledTaskJobService taskJobService;

    /**
     * 用于存放已经执行的task.
     */
    private static final ConcurrentMap<String, ScheduledTask> taskMap = new ConcurrentHashMap<>();

    /**
     * 定时任务注册.
     */
    private ScheduledTaskRegistrar taskRegistrar;

    @Resource(name = "taskSchedulerPoolExecutor")
    private ThreadPoolTaskScheduler taskSchedulerPoolExecutor;


    /**
     * 发送邮件.
     */
    private static final String SEND_EMAILS = "sendEmails";

    /**
     * 发送短信.
     */
    private static final String SEND_MESSAGES = "sendMessages";

    @Override
    public void configureTasks(final ScheduledTaskRegistrar scheduledTaskRegistrar) {

        /*
            用户要求暂时关闭此处代码，等待通知
        taskRegistrar = scheduledTaskRegistrar;
        // 设置线程池
        scheduledTaskRegistrar.setScheduler(taskSchedulerPoolExecutor);

        // 1. 获取所有任务
        final List<ScheduledTask> initTaskList = scheduledTaskMapper.selectAll();

        // 2. 根据配置情况执行对应的任务
        if(CollectionUtils.isNotEmpty(initTaskList)) {
            initTaskList.forEach(scheduledTask -> {

                taskMap.put(scheduledTask.getId(), scheduledTask);

                scheduledTaskRegistrar.addTriggerTask(() -> handlerJob(scheduledTask), cronTrigger(scheduledTask));

            });
        }*/

    }

    /**
     * 根据每一个配置的cron表达式，返回执行周期
     * @param scheduledTask 定时任务
     * @return Trigger 定时器
     */
    private Trigger cronTrigger(final ScheduledTask scheduledTask) {
        return triggerContext -> {
            // 获取最新的配置数据
            final List<ScheduledTask> newTaskList = scheduledTaskMapper.selectAll();

            if (CollectionUtils.isEmpty(newTaskList)) {
                // 没有查到，证明数据删除了，手动设置停止
                scheduledTask.setState(ScheduledTaskStatusEnum.DISABLED.getCode());
                return null;
            }

            for (final ScheduledTask newScheduledTask : newTaskList) {
                if(taskMap.containsKey(newScheduledTask.getId())) {
                    // 在taskMap里的任务存在修改的可能
                    updateExistingTask(scheduledTask, newScheduledTask);
                } else {
                    // 不在taskMap里的就是新增的任务
                    addNewTask(newScheduledTask);
                }
            }

            final CronTrigger trigger = new CronTrigger(scheduledTask.getCron());
            return trigger.nextExecutionTime(triggerContext);
        };
    }

    /**
     * 更新存在的定时任务.
     * @param scheduledTask 旧的定时任务
     * @param newScheduledTask 新的定时任务
     */
    private void updateExistingTask(final ScheduledTask scheduledTask, final ScheduledTask newScheduledTask) {
        if (StringUtils.equals(newScheduledTask.getId(), scheduledTask.getId()) && (!StringUtils.equals(newScheduledTask.getCron(), scheduledTask.getCron())
            || (newScheduledTask.getState() != scheduledTask.getState()))){

            //如果修改，cron表达式修改 或者 关闭状态修改 则取最新的数据的cron表达式和关闭状态
            scheduledTask.setCron(newScheduledTask.getCron());
            scheduledTask.setState(newScheduledTask.getState());
        }
    }

    /**
     * 添加新的任务.
     * @param newScheduledTask 新的定时任务
     */
    private void addNewTask(final ScheduledTask newScheduledTask) {
        // 不在taskMap里的就是新增的任务
        taskMap.put(newScheduledTask.getId(), newScheduledTask);
        taskRegistrar.addTriggerTask(() -> handlerJob(newScheduledTask), cronTrigger(newScheduledTask)); // 添加新的任务
        taskRegistrar.setTriggerTasksList(taskRegistrar.getTriggerTaskList()); // 并添加到实际任务列表里
        taskRegistrar.afterPropertiesSet(); // 然后刷新
    }

    /**
     * 处理业务
     * @param scheduledTask 定时任务
     */
    private void handlerJob(final ScheduledTask scheduledTask) {

        if(0 != scheduledTask.getState()){
            return;
        }

        // 根据定时任务启用状态和通知方式处理业务
        switch (scheduledTask.getNotificationMode()) {
            case SEND_EMAILS:
                taskJobService.sendEmails(scheduledTask);
                break;
            case SEND_MESSAGES:
                taskJobService.sendMessages(scheduledTask);
                break;
            default:
                break;
        }

    }

}
